//#include "stdafx.h"
#include "OrNode.h"

bool COrNode::InputFromStream(istream& inStream)
{
	char strTemp[10001];
	if (!(inStream>>strTemp>>ModelID>>Level>>InstCount)) return false;
	if (!(inStream>>parseInfo>>createInfo>>fNeedMakeInstTree>>fNeedRefreshMRFScore)) return false;
	int i, tn;
	if (!(inStream>>tn)) return false;
	children.resize(tn); for ( i = 0; i < tn; ++i ) if (!(inStream>>children[i])) return false;
	if (!(inStream>>tn)) return false;
	fullIndex.resize(tn); for ( i = 0; i < tn; ++i ) if (!(inStream>>fullIndex[i])) return false;
	if (!(inStream>>tn)) return false;
	CenterIndex.resize(tn); for ( i = 0; i < tn; ++i ) if (!(inStream>>CenterIndex[i])) return false;
	if (!(inStream>>tn)) return false;
	ConstrainIndex.resize(tn); for ( i = 0; i < tn; ++i ) if (!(inStream>>ConstrainIndex[i])) return false;
	if (!(inStream>>tn)) return false;
	instances.resize(tn); for ( i = 0; i < tn; ++i ) if (!(instances[i].InputFromStream(inStream))) return false;
	if (!(inStream>>tn)) return false;
	fullInst.resize(tn); for ( i = 0; i < tn; ++i ) if (!(fullInst[i].InputFromStream(inStream))) return false;
	return true;
}

void COrNode::OutputToStream(ostream& outStream) const
{
	outStream
		<<endl<<"::OrNode"
		<<"\t"<<(ModelID<10 ? "0" : "")<<ModelID
		<<"\t"<<Level
		<<"\t"<<InstCount
		<<endl;
	outStream
		<<"\t"<<parseInfo
		<<"\t"<<createInfo
		<<"\t"<<fNeedMakeInstTree
		<<"\t"<<fNeedRefreshMRFScore
		<<endl;
	int i, tn;
	outStream<<(tn = (int)children.size())<<endl;
	for ( i = 0; i < tn; ++i ) outStream<<"\t"<<children[i];
	outStream<<endl;
	outStream<<(tn = (int)fullIndex.size())<<endl;
	for ( i = 0; i < tn; ++i ) outStream<<"\t"<<fullIndex[i];
	outStream<<endl;
	outStream<<(tn = (int)CenterIndex.size())<<endl;
	for ( i = 0; i < tn; ++i ) outStream<<"\t"<<CenterIndex[i];
	outStream<<endl;
	outStream<<(tn = (int)ConstrainIndex.size())<<endl;
	for ( i = 0; i < tn; ++i ) outStream<<"\t"<<ConstrainIndex[i];
	outStream<<endl;
	outStream<<(tn = (int)instances.size())<<endl;
	for ( i = 0; i < tn; ++i ) { instances[i].OutputToStream(outStream); outStream<<endl; }
	outStream<<(tn = (int)fullInst.size())<<endl;
	for ( i = 0; i < tn; ++i ) { fullInst[i].OutputToStream(outStream); outStream<<endl; }
}

COrNode::COrNode(void)
{
	parseInfo				= false;
	createInfo				= false;

	fNeedRefreshMRFScore	= false;
	fNeedMakeInstTree		= false;
}

COrNode::~COrNode(void)
{
}

int	COrNode::BottomUpSearch(ModelTreeType &model, CHiBoostImageEntity &entity, InstanceTreeType &tree, const char* ccpPN_ParseLog)
{
	COrNodeModel	&CurrModel	= model.OrModels[ModelID];
	int				ChildCount, InstanceCount, FullCount;
	int				Index, FIndex, Count;
	int				ret;

	if (parseInfo)
	{
		return	1;
	}

	instances.clear();
	ChildCount		= (int) children.size();
	InstanceCount	= 0;
	FullCount		= 0;
	for ( int i = 0; i < ChildCount; i++ )
	{
		ret				= tree.AndNodes[children[i]].BottomUpSearch(model, entity, tree, ccpPN_ParseLog);
		InstanceCount	+= (int) tree.AndNodes[children[i]].instances.size();
		FullCount		+= (int) tree.AndNodes[children[i]].fullInst.size();
	}

	Index	= 0;
	FIndex	= 0;
	Count	= 0;
	instances.reserve(InstanceCount);
	fullInst.reserve(FullCount);
	fullIndex.reserve(FullCount);
	for ( int t = 0;  t < ChildCount; t++ )
	{
		InstanceCount	= (int) tree.AndNodes[children[t]].instances.size();
		for ( int i = 0; i < InstanceCount; i++ )
		{
			instances.push_back(tree.AndNodes[children[t]].instances[i]);
			instances[Index].Score	+= log(CurrModel.Weights[t]);
			instances[Index].source.clear();
			instances[Index].source.push_back(t);
			instances[Index].source.push_back(i);
			instances[Index].center.OrIndex = t;
			Index++;
		}

		FullCount	= (int) tree.AndNodes[children[t]].fullInst.size();
		for ( int i = 0; i < FullCount; i++ )
		{
			fullInst.push_back(tree.AndNodes[children[t]].fullInst[i]);
			fullIndex.push_back(tree.AndNodes[children[t]].fullIndex[i]);
			fullInst[FIndex].Score	+= log(CurrModel.Weights[t]);
			fullInst[FIndex].source.clear();
			fullInst[FIndex].source.push_back(t);
			fullInst[FIndex].source.push_back(i);
			fullInst[FIndex].center.OrIndex = t;
			if (fullIndex[FIndex] >= 0)
			{
				fullIndex[FIndex]	+= Count;
			}
			FIndex++;
		}

		Count	+= InstanceCount;
	}

	InstCount	= (int) instances.size();
	parseInfo	= true;
	return	1;
}

int COrNode::FillInInstInTree(InstanceTreeType &tree, InstanceTreeType &tree_fillin, int InstID)
{
	int		ChildCount	= (int) children.size();
	int		ret;

	for ( int i = 0; i < ChildCount; i++ )
	{
		int	ChildID	= children[i];

		if (tree_fillin.AndNodes[ChildID].instances.size() == 1)
		{
			instances[InstID].source[0]	= i;
			instances[InstID].source[1]	= (int) tree.AndNodes[ChildID].instances.size();
			tree.AndNodes[ChildID].instances.push_back(tree_fillin.AndNodes[ChildID].instances[0]);
			ret	= tree.AndNodes[ChildID].FillInInstInTree(tree, tree_fillin, instances[InstID].source[1]);
		}
	}

	return	1;
}

void COrNode::RefreshMRFScore(ModelTreeType &model, InstanceTreeType& tree)
{
	if (!fNeedRefreshMRFScore) return;
	fNeedRefreshMRFScore = false;

	COrNodeModel	&CurrModel	= model.OrModels[ModelID];
	int				ChildCount, InstanceCount;
	int				Index;

	instances.clear();
	ChildCount		= (int) children.size();
	InstanceCount	= 0;
	for ( int i = 0; i < ChildCount; i++ )
	{
		tree.AndNodes[children[i]].RefreshMRFScore(model, tree);
		InstanceCount	+= (int) tree.AndNodes[children[i]].instances.size();
	}

	Index	= 0;
	instances.reserve(InstanceCount);
	for ( int t = 0;  t < ChildCount; t++ )
	{
		InstanceCount	= (int) tree.AndNodes[children[t]].instances.size();
		for ( int i = 0; i < InstanceCount; i++ )
		{
			instances.push_back(tree.AndNodes[children[t]].instances[i]);
			instances[Index].Score	+= log(CurrModel.Weights[t]);
			instances[Index].source.clear();
			instances[Index].source.push_back(t);
			instances[Index].source.push_back(i);
			instances[Index].center.OrIndex = t;
			Index++;
		}
	}
}

int	COrNode::RemakeInstTree_NoEntity(ModelTreeType &model, InstanceTreeType &tree)
{
	if (!fNeedMakeInstTree) return 1;
	fNeedMakeInstTree = false;

	COrNodeModel	&CurrModel	= model.OrModels[ModelID];
	int				ChildCount, InstanceCount;
	int				Index;
	int				ret;

	instances.clear();
	ChildCount		= (int) children.size();
	InstanceCount	= 0;
	for ( int i = 0; i < ChildCount; i++ )
	{
		ret				= tree.AndNodes[children[i]].RemakeInstTree_NoEntity(model, tree);
		InstanceCount	+= (int) tree.AndNodes[children[i]].instances.size();
	}

	Index	= 0;
	instances.reserve(InstanceCount);
	for ( int t = 0;  t < ChildCount; t++ )
	{
		InstanceCount	= (int) tree.AndNodes[children[t]].instances.size();
		for ( int i = 0; i < InstanceCount; i++ )
		{
			instances.push_back(tree.AndNodes[children[t]].instances[i]);
			instances[Index].Score	+= log(CurrModel.Weights[t]);
			instances[Index].source.clear();
			instances[Index].source.push_back(t);
			instances[Index].source.push_back(i);
			instances[Index].center.OrIndex = t;
			Index++;
		}
	}

	return	1;
}

int	COrNode::MakeInstTree(ModelTreeType &model, CHiBoostImageEntity &entity, InstanceTreeType &tree, bool fComputeAppearanceScore)
{
	if (!fNeedMakeInstTree) return 1;
	fNeedMakeInstTree = false;

	COrNodeModel	&CurrModel	= model.OrModels[ModelID];
	int				ChildCount, InstanceCount;
	int				Index;
	int				ret;

	instances.clear();
	ChildCount		= (int) children.size();
	InstanceCount	= 0;
	for ( int i = 0; i < ChildCount; i++ )
	{
		ret				= tree.AndNodes[children[i]].MakeInstTree(model, entity, tree, fComputeAppearanceScore);
		InstanceCount	+= (int) tree.AndNodes[children[i]].instances.size();
	}

	Index	= 0;
	instances.reserve(InstanceCount);
	for ( int t = 0;  t < ChildCount; t++ )
	{
		InstanceCount	= (int) tree.AndNodes[children[t]].instances.size();
		for ( int i = 0; i < InstanceCount; i++ )
		{
			instances.push_back(tree.AndNodes[children[t]].instances[i]);
			instances[Index].Score	+= log(CurrModel.Weights[t]);
			instances[Index].source.clear();
			instances[Index].source.push_back(t);
			instances[Index].source.push_back(i);
			instances[Index].center.OrIndex = t;
			Index++;
		}
	}

	return	1;
}

double COrNode::AnalyseScore(
	vector<double>& DstScoreList_SubTree, vector<double>& DstScoreList_PerNode,
	CHiBoostImageEntity &entity, InstanceTreeType &tree, int InstID
	)
{
	int ChildID, ChildInstID;
	ChildID		= instances[InstID].source[0];
	ChildInstID	= instances[InstID].source[1];
	return tree.AndNodes[children[ChildID]].AnalyseScore(DstScoreList_SubTree, DstScoreList_PerNode, entity, tree, ChildInstID);
}

int	COrNode::UpdateParameters(
	ModelTreeType &model, ModelTreeType &NewModel,
	CHiBoostImageEntity &entity,
	InstanceTreeType &tree, InstanceTreeType &ground_tree,
	int InstID,
	double UpdatingWeight)
{
	COrNodeModel	&CurrModel	= model.OrModels[ModelID];
	int				ChildID, ChildInstID;
	int				ret;

	ChildID		= instances[InstID].source[0];
	ChildInstID	= instances[InstID].source[1];
	ret			= tree.AndNodes[children[ChildID]].UpdateParameters(model, NewModel, entity, tree, ground_tree, ChildInstID, UpdatingWeight);
	return	1;
}

int COrNode::AddSearchCenterIndex(ModelTreeType &model, InstanceTreeType &tree, ArcModelType &Rule, bool NxtStatus)
{
	int		ChildCount	= (int) children.size();
	int		ret;

	for ( int i = 0; i < ChildCount; i++ )
	{
		ret			= tree.AndNodes[children[i]].AddSearchCenterIndex(model, tree, Rule, NxtStatus);
		CenterIndex	= tree.AndNodes[children[i]].CenterIndex;
	}

	return	1;
}

int COrNode::SetNodeSearchStatus(ModelTreeType &model, InstanceTreeType &tree)
{
	int		ChildCount	= (int) children.size();
	int		ret;

	for ( int i = 0; i < ChildCount; i++ )
	{
		ret			= tree.AndNodes[children[i]].SetNodeSearchStatus(model, tree);
		parseInfo	= tree.AndNodes[children[i]].parseInfo ? parseInfo : false;
	}

	return	1;
}

int COrNode::MakeMissLeafNodes(ModelTreeType &model, CHiBoostImageEntity &entity, InstanceTreeType &tree, BasicInstInfoType &center, vector<BasicNodePairType> &LeafNodes)
{
	int		ChildID	= center.OrIndex;
	int		ret;

	ret	= tree.AndNodes[children[ChildID]].MakeMissLeafNodes(model, entity, tree, center, LeafNodes);
	return	1;
}

int COrNode::MakeSearchConstrain(ModelTreeType &model, InstanceTreeType &tree, CHiBoostImageEntity &entity)
{
	int		ChildCount	= (int) children.size();
	int		ChildID, ChildNodeID, InstID;
	int		ret;

	if (ModelID == model.Root)
	{
		for ( int i = 0; i < (int) tree.AndNodes.size(); i++ )
		{
			tree.AndNodes[i].ConstrainIndex.assign(tree.AndNodes[i].instances.size(), 0);
		}

		for ( int i = 0; i < (int) tree.OrNodes.size(); i++ )
		{
			tree.OrNodes[i].ConstrainIndex.assign(tree.OrNodes[i].instances.size(), 0);
		}

		ConstrainIndex.assign(instances.size(), 1);
	}

	for ( int i = 0; i < (int) instances.size(); i++ )
	{
		if (ConstrainIndex[i] == 1)
		{
			ChildID		= instances[i].source[0];
			InstID		= instances[i].source[1];
			ChildNodeID	= children[ChildID];
			tree.AndNodes[ChildNodeID].ConstrainIndex[InstID]	= 1;
		}
	}

	for ( int i = 0; i < ChildCount; i++ )
	{
		ret	= tree.AndNodes[children[i]].MakeSearchConstrain(model, tree, entity);
	}

	return	1;
}

void COrNode::CreateNaiveModelFromNodes(ModelTreeType &model, InstanceTreeType &tree)
{
	if (createInfo) return;

	COrNodeModel	&CurrModel	= model.OrModels[ModelID];
	int				ChildCount	= (int) children.size();
	int				InstCount, ChildID, Index;

	CurrModel.ModelCount	= ChildCount;
	CurrModel.Weights.assign(ChildCount, 1.0);

	InstCount	= 0;
	for ( int i = 0; i < ChildCount; i++ )
	{
		ChildID		= children[i];
		tree.AndNodes[ChildID].CreateNaiveModelFromNodes(model, tree);
		InstCount	+= (int) tree.AndNodes[ChildID].instances.size();
	}

	Index	= 0;
	instances.clear();
	instances.reserve(InstCount);
	for ( int t = 0; t < ChildCount; t++ )
	{
		InstCount	= (int) tree.AndNodes[children[t]].instances.size();
		for ( int i = 0; i < InstCount; i++ )
		{
			instances.push_back(tree.AndNodes[children[t]].instances[i]);
			instances[Index].Score	+= log(CurrModel.Weights[t]);
			instances[Index].source.clear();
			instances[Index].source.push_back(t);
			instances[Index].source.push_back(i);
			instances[Index].center.OrIndex = t;
			Index++;
		}
	}

	this->InstCount = InstCount;

	createInfo	= true;
}

